package main

import (
	"context"
	"github.com/pkg/errors"
	"gocamp2022/shutdown/base"
	"gocamp2022/shutdown/gcache"
	"gocamp2022/shutdown/routers"
	"golang.org/x/sync/errgroup"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

// server
type server struct {
	baseServices []base.BaseService // 基础服务-如数据库、redis等
	initFuncs    []func() error     // 初始化操作-在基础服务初始化之后初始化
	closeFuncs   []func() error     // 退出操作-在基础服务关闭之前关闭
	httpsrvs     []*httpsrv         // http server -多个
}

// httpsrv http服务
type httpsrv struct {
	srv  *http.Server
	name string // 服务名称
	mux  *httpMux
}

func (h *httpMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h.reject {
		w.WriteHeader(http.StatusServiceUnavailable)
		_, _ = w.Write([]byte("服务已关闭"))
		return
	}

	h.ServeMux.ServeHTTP(w, r)
}

type httpMux struct {
	*http.ServeMux
	reject bool
}

// RegisterInitFunc 注册初始化操作
func (s *server) RegisterInitFunc(fn ...func() error) {
	s.initFuncs = append(s.initFuncs, fn...)
}

// RegisterCloseFunc 注册关闭操作
func (s *server) RegisterCloseFunc(fn ...func() error) {
	s.closeFuncs = append(s.closeFuncs, fn...)
}

// RegisterHttpServer 注册http server
func (s *server) RegisterHttpServer(srvs ...*httpsrv) {
	for i := 0; i < len(srvs); i++ {
		s.httpsrvs = append(s.httpsrvs, srvs[i])
	}
}

// Run 启动服务
func (s *server) Run() {
	// 初始化
	if err := s.Init(); err != nil {
		log.Println("初始化失败:", err)
		os.Exit(1)
		return
	}

	// 初始化http server
	for _, srv := range s.httpsrvs {
		go func(server *httpsrv) {
			if err := server.srv.ListenAndServe(); err != nil {
				if err == http.ErrServerClosed {
					log.Println("http服务-" + server.name + "已关闭")
				} else {
					log.Println("http服务-"+server.name+"启动失败:", err)
					os.Exit(1)
				}
			}
		}(srv)
	}
}

// Init 初始化
func (s *server) Init() error {
	var egg0 errgroup.Group

	for _, service := range s.baseServices {
		egg0.Go(service.Init)
	}

	if err := egg0.Wait(); err != nil {
		return errors.Wrap(err, "初始化基础服务失败")
	}
	var egg errgroup.Group
	for _, fn := range s.initFuncs {
		egg.Go(fn)
	}

	if err := egg.Wait(); err != nil {
		return err
	}

	return nil
}

// Close 关闭http服务及其它操作
func (s *server) Close(ctx context.Context) {

	n := len(s.httpsrvs) + len(s.closeFuncs)

	if n == 0 {
		log.Println("待关闭任务列表为空")
		return
	}

	var wg sync.WaitGroup

	wg.Add(n)

	for i := 0; i < len(s.httpsrvs); i++ {
		go func(server *httpsrv) {
			defer wg.Done()
			if err := server.srv.Shutdown(ctx); err != nil {
				log.Printf("关闭http服务失败:%v\n", err)
			}
		}(s.httpsrvs[i])
	}

	for _, fn := range s.closeFuncs {
		go func(fn func() error) {
			defer wg.Done()
			if err := fn(); err != nil {
				log.Printf("执行关闭操作失败:%v\n", err)
			}
		}(fn)
	}

	var wgChan = make(chan struct{})

	go func() {
		wg.Wait()
		close(wgChan)
	}()

	select {
	case <-ctx.Done():
		log.Println("执行关闭操作超时")
	case <-wgChan:
		log.Println("执行关闭操作成功")
	}
}

// ShutDown 在xx时间内关闭服务
func (s *server) ShutDown(t time.Duration) {
	// 关闭http服务及其它操作
	ctx, cancel := context.WithTimeout(context.Background(), t)
	defer cancel()
	s.Close(ctx)

	// 关闭基础服务
	ctx2, cancel := context.WithTimeout(context.Background(), t)
	defer cancel()
	s.CloseBase(ctx2)

}

// RegisterBaseService 注册基础服务
func (s *server) RegisterBaseService(services ...base.BaseService) {
	for i := 0; i < len(services); i++ {
		s.baseServices = append(s.baseServices, services[i])
	}
}

func (s *server) CloseBase(ctx context.Context) {
	if len(s.baseServices) == 0 {
		return
	}

	var wg sync.WaitGroup
	wgChan := make(chan struct{})
	wg.Add(len(s.baseServices))

	for i := 0; i < len(s.baseServices); i++ {
		ser := s.baseServices[i]
		go func() {
			defer wg.Done()
			if err := ser.Close(); err != nil {
				log.Printf("关闭基础服务失败:%v\n", err)
			}
		}()
	}

	go func() {
		wg.Wait()
		wgChan <- struct{}{}
	}()

	select {
	case <-wgChan:
		log.Println("所有基础服务关闭成功")
	case <-ctx.Done():
		log.Println("关闭基础服务超时")
	}

}

// initHttpSrv 初始化http server-对外
func initHttpSrv() *httpsrv {

	mux := &http.ServeMux{}

	// 注册路由
	routers.InitRouter(mux)

	server := &http.Server{
		Handler: mux,
		Addr:    ":8080",
	}

	srv := &httpsrv{
		srv:  server,
		name: "http-outer",
		mux: &httpMux{
			ServeMux: mux,
		},
	}

	return srv
}

// initHttpSrvInner 初始化http server-对内
func initHttpSrvInner() *httpsrv {

	mux := &http.ServeMux{}

	// 注册路由
	routers.InitRouterInner(mux)

	server := &http.Server{
		Addr: "127.0.0.1:8081",
	}

	srv := &httpsrv{
		srv:  server,
		name: "http-inner",
		mux: &httpMux{
			ServeMux: mux,
		},
	}

	return srv
}

func main() {
	gserver := server{}
	// 注册基础服务
	gserver.RegisterBaseService(&base.DBService{}, &base.RedisService{})
	// 注册初始化操作
	gserver.RegisterInitFunc()
	// 注册关闭操作
	gserver.RegisterCloseFunc(gcache.BrushCacheToDB)

	// 注册http服务
	gserver.RegisterHttpServer(initHttpSrv(), initHttpSrvInner())

	// 启动服务
	gserver.Run()

	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt, syscall.SIGTERM, syscall.SIGKILL)

	<-quit
	log.Println("开始关闭服务...")

	// 关闭服务
	gserver.ShutDown(time.Second * 5)

	log.Println("服务已关闭")

}
